from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.select import Select
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support import expected_conditions as EC

from utils.logger import Log
from utils.read_element import ElementYamlUtils
from utils.get_driver import driver
from utils.times import strftime

from global_conf import config

import time
import os

log = Log(os.path.basename(__file__))

class BasePage(object):

    def __init__(self):
        self.driver = driver
        self.action = ActionChains(self.driver)

    def find_element(self, locator, timeout=config.EXPLICITLY_WAIT_TiME, poll_frequency=0.5):

        if locator.timeout is not None:
            timeout = locator.timeout

        element = WebDriverWait(self.driver, timeout=timeout, poll_frequency=poll_frequency).until(
            EC.visibility_of_element_located((locator.locator_type,locator.locator_value)))
        self.high_light_element(element)
        log.info("查找元素：%s" % str(locator))
        return element

    def find_elements(self, locator, timeout=config.EXPLICITLY_WAIT_TiME, poll_frequency=0.5):

        if locator.timeout is not None:
            timeout = locator.timeout
        
        elements = WebDriverWait(self.driver, timeout=timeout, poll_frequency=poll_frequency).until(
            EC.visibility_of_all_elements_located((locator.locator_type,locator.locator_value)))
        log.info("查找元素：%s" % str(locator))
        return elements

    def element_is_display(self, locator):
        """
        获取元素来显示,返回结果为真或假.
        """
        ele = self.find_element(locator)
        return ele.is_displayed()

    def open_url(self, url, page_load_timeout=30):
        """打开网址并验证"""
        try:
            self.driver.set_page_load_timeout(page_load_timeout)
            self.driver.get(url)
            log.info("打开网页：%s" % url)
        except TimeoutException:
            self.driver.execute_script('window.stop()')  # 执行Javascript来停止页面加载
            log.error("打开%s超时请检查网络或网址服务器" % url)

    def pause(self, seconds):
        """等待固定的时间"""
        time.sleep(seconds)
        log.info("暂停{}秒 ".format(seconds))

    def input(self, locator, text):
        ele = self.find_element(locator)
        ele.send_keys(text)
        log.info("文本框:{} 输入文本：{}".format(locator, text))

    def click(self, locator):
        """点击元素"""

        WebDriverWait(self.driver, timeout=config.EXPLICITLY_WAIT_TiME, poll_frequency=0.5).until(
            EC.element_to_be_clickable((locator.locator_type, locator.locator_value)))

        ele = self.find_element(locator)
        try:
            ele.click()
            log.info("点击元素：{}".format(locator))
        except Exception as e:
            log.error("点击元素时出现异常{}".format(e))
            self.execute_js('arguments[0].click()', ele)

    def right_click(self, locator):
        """
        右键单击元素.
        """
        ele = self.find_element(locator)
        ActionChains(self.driver).context_click(ele).perform()

    def double_click(self, locator):
        """
        双击元素.
        """
        ele = self.find_element(locator)
        ActionChains(self.driver).double_click(ele).perform()

    def click_link_text(self, text):
        """
        单击链接文本中的元素
        用法:
        driver.click_link_text("新闻")
        """
        self.driver.find_element_by_partial_link_text(text).click()

    def click_area(self, x, y):
        """点击屏幕上任意位置"""
        self.action.move_by_offset(x, y).perform()
        log.info("点击屏幕,坐标为:({},{})".format(x, y))

    def move_to_element(self, locator):
        """移动到指定元素上(悬停)"""
        ele = self.find_element(locator)
        self.action.move_to_element(ele).perform()
        log.info("移动到{}上".format(ele))

    def move_click_element(self, locator):
        """移动到元素并点击"""
        ele = self.find_element(locator)
        self.action.move_to_element(ele).click().perform()
        log.info("移动到{}上并点击".format(ele))

    def click_and_hold(self, locator, x, y):
        """点击元素并按住，移动到指定位置上"""
        ele = self.find_element(locator)
        self.action.drag_and_drop_by_offset(ele, x, y)
        log.info("拖放元素: {}".format(ele))

    def drag_element_from_to(self, source_locator, target_locator):

        """
           把一个元素拖到一定的距离,然后把它放下.
        """
        source = self.find_element(source_locator)
        target = self.find_element(target_locator)
        ActionChains(self.driver).drag_and_drop(source, target).perform()

    def open_new_window(self, locator):
        """
        打开新窗口并切换到新打开的窗口.
        用法:
        传入一个点击后会跳转的元素
        """
        original_window = self.driver.current_window_handle
        el = self.find_element(locator)
        el.click()
        all_handles = self.driver.window_handles
        for handle in all_handles:
            if handle != original_window:
                self.driver.switch_to.window(handle)

    def select(self, locator, value):
        """在下拉菜单中选择"""
        ele = self.find_element(locator)
        Select(ele).select_by_value(value)
        log.info("下拉框:{},根据选项值选择:{} ".format(ele, value))

    def is_selected(self, locator):
        """
            验证元素是否选中
        """
        return self.find_element(locator).is_selected()

    def switch_to_frame(self, locator):
        ele = self.find_element(locator)
        self.driver.switch_to.frame(ele)
        log.info("切换到frame：{}".format(locator))

    def switch_to_default_frame(self):
        self.driver.switch_to.default_content()
        log.info("切换到默认frame")

    def get_text(self, locator):
        ele = self.find_element(locator)

        ele_text = ele.text

        # 如果通过text属性无法获取文本值,就通过元素属性value来获取
        if ele_text is None or ele_text == '':
            ele_text = ele.get_attribute('value')

        # 如果通过属性value无法获取文本值,就通过元素属性innerText来获取
        if ele_text is None or ele_text == '':
            ele_text = ele.get_attribute('innerText')

        log.info("获取文本：{}".format(ele_text))
        return ele_text

    def upload_file(self, locator, upload_file_path):

        ele = self.find_element(locator)
        ele.clear()
        ele.sendKeys(upload_file_path)
        log.info("上传文件路径：{}".format(upload_file_path))

    @property
    def get_source(self):
        """获取页面源代码"""
        return self.driver.page_source

    def get_page_title(self):
        """
           获取当前页面的Title.
           用法:
           driver.get_page_title()
        """
        time.sleep(2)  # 防止运行过快,点击还未执行完毕就获取后续的元素
        return self.driver.title

    @property
    def get_page_url(self):
        """
        获取当前页面的URL地址.
        用法:
        driver.get_page_url()
        """
        return self.driver.current_url

    def shot_file(self):
        """截图"""

        file_path = os.path.join(config.SCREEN_PATH,strftime(fmt='%Y-%m-%d_%H-%M-%S.jpg'))

        log.info("错误截图,图片路径为：{}".format(file_path))
        return self.driver.save_screenshot(file_path)

    def high_light_element(self, element):
        """高亮元素"""
        self.driver.execute_script("arguments[0].setAttribute('style',arguments[1]);", element,
                                   "border:2px solid red;")

    def execute_js(self, js):

        self.driver.execute_script(js)

    def get_current_url(self):

        return self.driver.current_url()

    def add_cookie(self, cookie):

        self.driver.add_cookie(cookie)

    def get_cookies(self):

        return self.driver.get_cookies()

    def get_cookie(self, name):

        return self.driver.get_cookie(name)

    def delete_cookie(self, name):

        self.driver.delete_cookie(name)

    def delete_all_cookies(self):

        self.driver.delete_all_cookies()

    def forward(self):
        self.driver.forward()

    def back(self):
        self.driver.back()

    def refresh(self):
        """刷新页面F5"""
        self.driver.refresh()
        log.info("当前页面刷新完成")

    def close(self):

        self.driver.close()
        log.info("浏览器已关闭")

    def quit(self):

        self.driver.quit()
        log.info("浏览器已关闭")

    def get_locator(self,locator_name):
        '''从yaml文件中获取元素对象'''

        elements = ElementYamlUtils(self.__class__.__name__)
        return elements[locator_name]